package bb.lanxing.lib.devices.core.ble;

import static com.bes.bessdk.BesSdkConstants.BES_GATT_DESCRIPTOR_OTA_UUID;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import com.bes.bessdk.BesSdkConstants;
import com.bes.bessdk.connect.BleConnector;
import com.bes.bessdk.scan.BtHeleper;
import com.bes.bessdk.service.base.BesServiceConfig;
import com.bes.bessdk.service.base.BesServiceListener;
import com.bes.sdk.device.HmDevice;
import com.bes.sdk.message.Constants;
import com.bes.sdk.utils.DeviceProtocol;
import com.besall.allbase.view.activity.chipstoollevel4.protocol.ProtocolPresenter;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

import bb.lanxing.lib.devices.api.PeerDevice;
import bb.lanxing.lib.devices.api.SmartDevice;
import bb.lanxing.lib.devices.ble.BLEAttributes;
import bb.lanxing.lib.devices.core.AbstractPeerDevice;
import bb.lanxing.lib.devices.core.scanner.BleDeviceScanner;
import bb.lanxing.lib.devices.core.utils.DeviceHelper;
import bb.lanxing.model.database.Device;
import gov.nist.core.Separators;

public abstract class AbsBleDevice extends AbstractPeerDevice implements IGattClient, SpecificationAttributes, Thread.UncaughtExceptionHandler {
    protected static final int OP_REQUEST_MTU_TIMEOUT = 0x410000;
    private static final String TAG = "AbsBleDevice";
    private static final int DEFAULT_CONNECT_TIMEOUT = 30000;
    private static final int DEFAULT_DISCONNECT_TIMEOUT = 30000;
    private static final int DEFAULT_DISCOVER_TIMEOUT = 30000;
    private static final int DEFAULT_MTU = 23;
    private static final int DEFAULT_MTU_CHANGE_TIMEOUT = 30000;
    private static final int DEFAULT_RECONNECT_DELAY = 20000;
    private static final int DEFAULT_RECONNECT_SCAN_DURATION = 10000;
    private static final int DEFAULT_REQUEST_MTU = 512;
    private static final int OP_CLOSE = 0x100000;
    private static final int OP_CONNECT = 0x10000;
    private static final int OP_DISCONNECT = 0x80000;
    private static final int OP_DISCOVER_SERVICES = 0x40000;
    private static final int OP_DISPATCH_DEVICE_STATUS = 0x210000;
    private static final int OP_DISPATCH_STATUS = 0x200000;
    private static final int OP_EXECUTE_REQUEST = 0x400000;
    private static final int OP_RECONNECT = 0x20000;
    private static final int OP_SHIFT = 0x10;
    private static final AtomicInteger mConnectingDevices = new AtomicInteger(0);
    private final Object mLock;
    protected boolean disConnectFromUser;
    protected Context mAppContext;
    protected BluetoothAdapter mBluetoothAdapter;
    protected BluetoothDevice mBluetoothDevice;
    protected BluetoothGatt mBluetoothGatt;
    protected GattClientHandler mLocalHandler;
    protected int mtuExchanged;
    private int battery;
    private String firmwareVersion;
    private String hardwareVersion;
    private int heartRateBodyLocation;
    private volatile int mCurrentConnectionState;
    private volatile int mCurrentDeviceState;
    private volatile String mCurrentTransFileName;
    private String mDeviceAddress;
    private BluetoothGattCallback mGattCallback;
    private boolean mNotify;
    private int mRequestResult;
    private BleDeviceScanner mScanner;
    private volatile int mTargetState;
    private String manufacturer;
    private String model;
    private String serial;
    private String softwareVersion;

    public AbsBleDevice(SmartDevice smartDevice) {
        super(smartDevice);
        this.mLock = new Object();
        this.mCurrentDeviceState = PeerDevice.STATE_DEVICE_STATE_FREE;
        this.mCurrentTransFileName = "";
        this.mtuExchanged = DEFAULT_MTU;
        this.disConnectFromUser = false;
    }

    @Override
    public int getProtocol() {
        return 1;
    }

    public void handleMtuRequest(int i, int i2) {
    }

    protected void initBeforeConnect() {
    }

    public void onServicesDiscovered() {
    }

    protected boolean onStateChanged(int i, int i2) {
        return false;
    }

    public boolean shouldAutoConnection() {
        return true;
    }

    protected boolean shouldRefreshCache() {
        return false;
    }

    public void init(Context context, String str, BluetoothGattCallback bluetoothGattCallback) {
        this.mAppContext = context;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "init: permission check not granted!");
                return;
            }
        }
        this.mGattCallback = bluetoothGattCallback;
        this.mDeviceAddress = str;
        this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    protected synchronized void initLocalScheduler() {
        if (this.mLocalHandler != null) {
            return;
        }
        HandlerThread handlerThread = new HandlerThread(getName() == null ? getAddress() : getName());
        handlerThread.setUncaughtExceptionHandler(this);
        handlerThread.start();
        this.mLocalHandler = new GattClientHandler(this, handlerThread.getLooper());
    }

    public Handler getHandler() {
        return this.mLocalHandler;
    }

    public int getHeartRateBodyLocation() {
        return this.heartRateBodyLocation;
    }

    public void setHeartRateBodyLocation(int i) {
        this.heartRateBodyLocation = i;
    }

    public int getBattery() {
        return this.battery;
    }

    public void setBattery(int i) {
        this.battery = i;
    }

    public String getFirmwareVersion() {
        return this.firmwareVersion;
    }

    public void setFirmwareVersion(String str) {
        this.firmwareVersion = str;
    }

    public String getManufacturer() {
        return this.manufacturer;
    }

    public void setManufacturer(String str) {
        this.manufacturer = str;
    }

    public String getModel() {
        return this.model;
    }

    public void setModel(String str) {
        // Log.d("wangsm_bt", " setMode str: " + str);
        this.model = str;
    }

    public String getSerial() {
        return this.serial;
    }

    public void setSerial(String str) {
        // Log.d("wangsm_bt", " setSerial str: " + str);
        this.serial = str;
    }

    public String getHardwareVersion() {
        return this.hardwareVersion;
    }

    public void setHardwareVersion(String str) {
        this.hardwareVersion = str;
    }

    public String getSoftwareVersion() {
        return this.softwareVersion;
    }

    public void setSoftwareVersion(String str) {
        this.softwareVersion = str;
    }

    @Override
    public BluetoothDevice getBluetoothDevice() {
        return this.mBluetoothDevice;
    }

    public boolean isDisConnectFromUser() {
        return this.disConnectFromUser;
    }

    @Override
    public void setDisConnectFromUser(boolean z) {
        this.disConnectFromUser = z;
    }

    @Override
    public String getAddress() {
        String str = this.mDeviceAddress;
        if (str != null) {
            return str;
        }
        BluetoothDevice bluetoothDevice = this.mBluetoothDevice;
        if (bluetoothDevice == null) {
            return null;
        }
        return bluetoothDevice.getAddress();
    }

    @Override
    public BluetoothGatt getBluetoothGatt() {
        return this.mBluetoothGatt;
    }

    public BluetoothGattCallback getBluetoothGattCallback() {
        return this.mGattCallback;
    }

    @Override
    public void connect() {
        initLocalScheduler();
        this.mLocalHandler.sendEmptyMessage(OP_CONNECT);
    }

    @Override
    public void disconnect() {
        Log.d(TAG, "disconnect...");
        setDisConnectFromUser(true);
        GattClientHandler gattClientHandler = this.mLocalHandler;
        if (gattClientHandler != null) {
            gattClientHandler.sendEmptyMessage(OP_DISCONNECT);
        }
    }

    @Override
    public boolean isConnected() {
        return this.mCurrentConnectionState == PeerDevice.STATE_CONNECTED || this.mCurrentConnectionState == 8;
    }

    @Override
    public boolean isConnecting() {
        return this.mCurrentConnectionState == PeerDevice.STATE_CONNECTING;
    }

    private void reconnect() {
        this.mLocalHandler.sendEmptyMessageDelayed(OP_RECONNECT, DEFAULT_RECONNECT_DELAY);
    }

    @Override
    public void close() {
        GattClientHandler gattClientHandler = this.mLocalHandler;
        if (gattClientHandler == null || gattClientHandler.hasMessages(OP_CLOSE)) {
            Log.e(TAG, "Already closed");
            return;
        }
        this.mLocalHandler.removeMessages(OP_EXECUTE_REQUEST);
        synchronized (this.mLock) {
            this.mLock.notifyAll();
        }
        this.mLocalHandler.sendEmptyMessage(OP_CLOSE);
    }

    @Override
    public int getConnectionState() {
        return this.mCurrentConnectionState;
    }

    @Override
    public int getDeviceState() {
        return this.mCurrentDeviceState;
    }

    protected void connectBesDevice() {

        // the whether the device has been bonded,if not,return,not connect.
        // BtHeleper.getBondedDevices(mAppContext);
        BleConnector bleConnector = BleConnector.getsConnector(mAppContext, null, null);
        ArrayList<HmDevice> curConBleDevices = bleConnector.getCurConnectDevices();
        if (curConBleDevices != null && !curConBleDevices.isEmpty()) {
            Log.d(TAG, " the device has connected ");
            return;
        }
        Log.d(TAG, " connect the bes device");
        SmartDevice smartDevice = getDevice();
        // Log.d(TAG," the device address which should be connected: " + smartDevice.getAddress());
        boolean isBonded = BtHeleper.checkDeviceIsBonded(mAppContext, smartDevice.getAddress());
        if (!isBonded) {
            Log.d(TAG, " the device is not bonded,return,not to connect ");
            return;
        }

        HmDevice hmDevice = new HmDevice();
        hmDevice.setDeviceName(smartDevice.getName());
        hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_BLE);
        hmDevice.setBleAddress(smartDevice.getAddress());
        hmDevice.setRssi(smartDevice.getRssi());

        BesServiceConfig serviceConfig = new BesServiceConfig();
        serviceConfig.setDeviceProtocol(DeviceProtocol.PROTOCOL_BLE);
        serviceConfig.setTotaConnect(false);
        serviceConfig.setUseTotaV2(false);
        serviceConfig.setServiceUUID(BesSdkConstants.ALIPAY_SERIVICE_UUID);
        serviceConfig.setCharacteristicsUUID(BesSdkConstants.ALIPAY_CHARACTERISTICRX_UUID);// ALIPAY_CHARACTERISTICRX_UUID
        // serviceConfig.setCharacteristicsTX(BesSdkConstants.ALIPAY_CHARACTERISTICTX_UUID);
        serviceConfig.setDescriptorUUID(BES_GATT_DESCRIPTOR_OTA_UUID);
        serviceConfig.setDevice(hmDevice);
        /*
         * BesSdkConstants.BesConnectState besConnectState = BTService.getDeviceConnectState(mAppContext,
         * serviceConfig); Log.d(TAG, " the address:" + smartDevice.getAddress() + " ,besConnectState= " +
         * besConnectState);
         */
        // if(besConnectState != BES_CONNECT){
//        bleConnector.disconnect(hmDevice);
        ProtocolPresenter protocolPresenter = ProtocolPresenter.getInstance();
        // protocolPresenter.setProtocolServiceListener(this);
        protocolPresenter.connectDevice(serviceConfig, new BesServiceListener() {
            @Override
            public void onTotaConnectState(boolean state, HmDevice hmDevice) {

            }

            @Override
            public void onErrorMessage(int msg, HmDevice hmDevice) {

            }

            @Override
            public void onStateChangedMessage(int msg, String msgStr, HmDevice hmDevice) {
                Log.i(TAG, "AbsBleDevice onStateChangedMessage msg = " + msg);
                Intent intent = new Intent();
                intent.setAction(Constants.ACTION_BES_BLE_CONNECT_STATE);
                intent.putExtra(Constants.KEY_CONN_STATE, msg);
                intent.putExtra(Constants.KEY_DEVICE, getDevice());
                mAppContext.sendBroadcast(intent);
            }

            @Override
            public void onSuccessMessage(int msg, HmDevice hmDevice) {
                if (msg == Constants.APP_UNBIND_DEVICE_SUCCESS) {
                    unBindFinish(hmDevice.getBleAddress());
                }
            }
        }, mAppContext);
        // }
    }

    /**
     * 解绑设备
     */
    private void unBindFinish(@NonNull String address) {
        ProtocolPresenter protocolPresenter = ProtocolPresenter.getInstance();
        if (null != protocolPresenter) {
            Log.d(TAG, "AbsBleDevice unbind the device finish");
            BtHeleper.unBondedBleDevice(mAppContext, address);
            Device.deleteByAddress(address);
        }
    }

    protected void _connect() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "_connect: permission check not granted!");
                return;
            }
        }

        initBeforeConnect();
        if (this.mBluetoothGatt != null) {
            Log.d(TAG, "_connect :mBluetoothGatt not null , close & assign to null ");
            try {
                this.mBluetoothGatt.close();
            } catch (Throwable ignored) {
            }
            this.mBluetoothGatt = null;
            try {
                Thread.sleep(500L);
            } catch (InterruptedException ignored) {
            }
        }
        Log.d(TAG, "try to connect to " + getName());
        this.mNotify = false;
        initLocalScheduler();
        refreshGattClientState(PeerDevice.STATE_CONNECTING, PeerDevice.STATE_CONNECTED);
        BluetoothAdapter bluetoothAdapter = this.mBluetoothAdapter;
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
            reportError(ERROR_BLUETOOTH);
            refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED, IGattClient.ERROR_BLUETOOTH);
            return;
        }
        if (this.mBluetoothDevice == null) {
            String str = this.mDeviceAddress;
            if (str != null) {
                this.mBluetoothDevice = this.mBluetoothAdapter.getRemoteDevice(str);
            }
            if (this.mBluetoothDevice == null) {
                reportError(ERROR_NOT_FOUND_DEVICE);
                refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED, IGattClient.ERROR_NOT_FOUND_DEVICE);
                return;
            }
        }
        mConnectingDevices.incrementAndGet();
        BluetoothGatt bluetoothGatt = this.mBluetoothGatt;
        SmartDevice smartDevice = getDevice();
        Log.d(TAG, " OP_CONNECT: ");
        if (smartDevice != null && smartDevice.getType() == SmartDevice.TYPE_BES) {
            // int type = smartDevice.getType();
            // Log.d(TAG," the type is: " + type);
            boolean existDeviceConnected = DeviceHelper.isConnected(SmartDevice.TYPE_BES);
            Log.d(TAG, " existDeviceConnected: " + existDeviceConnected);
            if (!existDeviceConnected) {
                connectBesDevice();
            }
        } else if (bluetoothGatt != null && bluetoothGatt.getDevice() != null && this.mBluetoothGatt.getDevice().getAddress().equals(this.mDeviceAddress)) {
            this.mBluetoothGatt.connect();
        } else {
            this.mBluetoothGatt = this.mBluetoothDevice.connectGatt(this.mAppContext, false, this.mGattCallback, 2, 1);
        }
        if (this.mBluetoothGatt != null) {
            waitForRemoteDevice(mConnectingDevices.get() * DEFAULT_CONNECT_TIMEOUT);
            if (this.mCurrentConnectionState == PeerDevice.STATE_CONNECTED) {
                _discoverServices();
                if (this.mCurrentConnectionState == 8) {
                    this.mLocalHandler.removeMessages(OP_CONNECT);
                    this.mLocalHandler.removeMessages(OP_RECONNECT);
                    mConnectingDevices.decrementAndGet();
                    return;
                }
            }
        } else {
            reportError(ERROR_BLUETOOTH);
        }
        mConnectingDevices.decrementAndGet();
    }

    protected void _reconnect() {
        if (!this.mBluetoothAdapter.isEnabled()) {
            this.mLocalHandler.sendEmptyMessageDelayed(OP_RECONNECT, DEFAULT_RECONNECT_DELAY);
            return;
        }
        connect();
        this.mLocalHandler.sendEmptyMessageDelayed(OP_RECONNECT, DEFAULT_RECONNECT_DELAY);
    }

    protected void _disconnect() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "_disconnect: permission check not granted!");
                return;
            }
        }
        if (this.mBluetoothGatt == null) {
            Log.e(TAG, "No gatt client");
        } else if (this.mCurrentConnectionState != PeerDevice.STATE_DISCONNECTING && this.mCurrentConnectionState != PeerDevice.STATE_DISCONNECTED) {
            this.mNotify = false;
            refreshGattClientState(PeerDevice.STATE_DISCONNECTING, PeerDevice.STATE_DISCONNECTED);
            this.mBluetoothGatt.disconnect();
            waitForRemoteDevice(DEFAULT_DISCONNECT_TIMEOUT);
        }
    }

    public void _close() {
        BleDeviceScanner bleDeviceScanner = this.mScanner;
        if (bleDeviceScanner != null) {
            bleDeviceScanner.release();
            this.mScanner = null;
        }
        GattClientHandler gattClientHandler = this.mLocalHandler;
        if (gattClientHandler != null) {
            gattClientHandler.removeCallbacksAndMessages(null);
        }
        _disconnect();
        refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED);
        closeBluetoothGatt();
        this.mBluetoothDevice = null;
        final GattClientHandler gattClientHandler2 = this.mLocalHandler;

        gattClientHandler2.post(() -> {
            gattClientHandler2.mClientRef = null;
            gattClientHandler2.getLooper().quit();
            AbsBleDevice.this.mLocalHandler = null;
        });
        Log.d(TAG, "Close gatt client");
    }

    private synchronized void closeBluetoothGatt() {
        Log.d(TAG, "fuc closeBluetoothGatt: close & Assign to null");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "closeBluetoothGatt: permission check not granted!");
                return;
            }
        }
        if (this.mBluetoothGatt != null) {
            if (shouldRefreshCache()) {
                refreshDeviceCache();
            }
            this.mBluetoothGatt.close();
            this.mBluetoothGatt = null;
        }
    }

    protected void _discoverServices() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "_discoverServices: permission check not granted!");
                return;
            }
        }
        if (this.mBluetoothGatt == null) {
            return;
        }
        this.mNotify = false;
        refreshGattClientState(this.mCurrentConnectionState, 8);
        Log.d(TAG, "try to discover services: ");
        this.mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
        if (this.mBluetoothGatt.discoverServices()) {
            waitForRemoteDevice(DEFAULT_DISCOVER_TIMEOUT);
            if (this.mCurrentConnectionState != 8) {
                Log.e(TAG, "Not discover services");
                return;
            } else {
                Log.d(TAG, "Services discovered");
                return;
            }
        }
        Log.e(TAG, "Failed to start discover services");
    }

    private void refreshDeviceCache() {
        try {
            Method method = this.mBluetoothGatt.getClass().getMethod("refresh");
            boolean booleanValue = (Boolean) method.invoke(this.mBluetoothGatt, new Object[0]);
            Log.d(TAG, "Refreshing result: " + booleanValue);
        } catch (Exception e) {
            Log.e(TAG, "exception e=" + e);
        }
    }

    private void refreshGattClientState(int currentState, int targetState, int i3) {
        if (this.mCurrentConnectionState == currentState && this.mTargetState == targetState) {
            return;
        }
        boolean z = false;
        Log.d(TAG, String.format("onStateChanged: old currentState-> %d, old targetState-> %d,  currentState-> %d, targetState->%d", this.mCurrentConnectionState, this.mTargetState, currentState, targetState));
        if (currentState == this.mCurrentConnectionState) {
            z = true;
        }
        this.mCurrentConnectionState = currentState;
        this.mTargetState = targetState;
        if (z) {
            return;
        }
        if (this.mLocalHandler.getLooper() != Looper.myLooper()) {
            this.mLocalHandler.obtainMessage(OP_DISPATCH_STATUS, currentState, i3).sendToTarget();
        } else if (!onStateChanged(currentState, i3)) {
            notifyStateChanged(currentState, i3);
        }
    }

    public void refreshDeviceState(int newState, String str) {
        this.mCurrentTransFileName = str;
        if (this.mCurrentDeviceState == newState) {
            return;
        }
        this.mCurrentDeviceState = newState;
        Log.d(TAG, String.format("Device State Changed: old State-> %d, new State-> %d", this.mCurrentDeviceState, newState));
        if (this.mLocalHandler.getLooper() != Looper.myLooper()) {
            Log.d("wangsm_bt", " refreshDeviceState ,localHandler send msg");
            this.mLocalHandler.obtainMessage(OP_DISPATCH_DEVICE_STATUS, newState).sendToTarget();
        } else {
            Log.d("wangsm_bt", " refreshDeviceState ,notifyDeviceStateChanged");
            notifyDeviceStateChanged(newState);
        }
    }

    @Override
    public String getCurrentFileNameInTransfer() {
        return this.mCurrentTransFileName;
    }

    @Override
    public void notifyStateChanged(final int vState, final int errCode) {
        if (this.mLocalHandler == null || Looper.myLooper() == this.mLocalHandler.getLooper()) {
            super.notifyStateChanged(vState, errCode);
        } else {
            this.mLocalHandler.post(() -> AbsBleDevice.super.notifyStateChanged(vState, errCode));
        }
    }

    private void refreshGattClientState(int currentState, int targetState) {
        refreshGattClientState(currentState, targetState, IGattClient.ERROR_NONE);
    }

    private void wakeup() {
        synchronized (this.mLock) {
            this.mNotify = true;
            this.mLock.notifyAll();
        }
    }

    private void waitForRemoteDevice(int i) {
        Log.d(TAG, "waitForRemoteDevice: " + i);
        try {
            long uptimeMillis = SystemClock.uptimeMillis();
            synchronized (this.mLock) {
                if (!this.mNotify) {
                    this.mLock.wait(i);
                }
                if (!this.mNotify) {
                    reportError(ERROR_TIMEOUT);
                    refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED, IGattClient.ERROR_TIMEOUT);
                }
            }
            Log.d(TAG, "waitForRemoteDevice return: " + (SystemClock.uptimeMillis() - uptimeMillis));
        } catch (InterruptedException e) {
            Log.e(TAG, "exception e=" + e);
            refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED);
        }
    }

    public void syncState(int status, int newState) {
        int updatedState = PeerDevice.STATE_CONNECTED;
        Log.d(TAG, String.format("onConnectionStateChange: status->%d, newState->%d", status, newState));
        if (status != PeerDevice.STATE_NONE || newState == PeerDevice.STATE_NONE) {
            updatedState = PeerDevice.STATE_DISCONNECTED;
        } else if (newState == PeerDevice.STATE_CONNECTING) {
            updatedState = PeerDevice.STATE_CONNECTING;
        } else if (newState != PeerDevice.STATE_CONNECTED) {
            updatedState = newState != PeerDevice.STATE_DISCONNECTING ? PeerDevice.STATE_NONE : PeerDevice.STATE_DISCONNECTING;
        }
        if (status == PeerDevice.STATE_NONE && updatedState == this.mTargetState) {
            refreshGattClientState(this.mTargetState, this.mTargetState);
        } else {
            if (updatedState == PeerDevice.STATE_DISCONNECTED) {
                if (((this.mTargetState == this.mCurrentConnectionState && this.mCurrentConnectionState == 8) || status == GattError.GATT_ERROR_133) && shouldAutoConnection() && !isDisConnectFromUser()) {
                    refreshGattClientState(PeerDevice.STATE_DISCONNECTED, PeerDevice.STATE_DISCONNECTED, IGattClient.ERROR_CONNECT_LOSE);
                    reconnect();
                    setDisConnectFromUser(false);
                    return;
                }
                closeBluetoothGatt();
            } else {
                close();
            }
            refreshGattClientState(updatedState, updatedState, status);
            Log.e(TAG, GattError.parseConnectionError(status));
        }
        wakeup();
    }

    public void handleServicesDiscovered(int i) {
        if (i == 0) {
            refreshGattClientState(8, 8);
            this.mLocalHandler.sendEmptyMessage(OP_DISCOVER_SERVICES);
        }
        wakeup();
    }

    public void readFirmwareVersion() {
        // BluetoothGattService service;
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_FIRMWARE_CHARACTERISTIC)));
            }
        }
    }

    public void readSoftwareVersion() {
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_SOFTWARE_CHARACTERISTIC)));
            }
        }
    }

    public void readHardware() {
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_HARDWARE_CHARACTERISTIC)));
            }
        }
    }

    public void readModel() {
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_MODEL_CHARACTERISTIC)));
            }
        }
    }

    public void readSerial() {
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_SERIAL_CHARACTERISTIC)));
            }
        }
    }

    public void readManufacturer() {
        if (isServicesDiscovered()) {
            BluetoothGattService service = this.mBluetoothGatt.getService(BLE_DEVICE_INFORMATION_SERVICE);
            if (service != null) {
                enqueue(Request.newReadRequest(service.getCharacteristic(BLE_DEVICE_INFORMATION_MANUFACTURER_CHARACTERISTIC)));
            }
        }
    }

    public void readBattery() {
        BluetoothGattService service = this.mBluetoothGatt.getService(BLE_BATTERY_SERVICE);
        if (service != null) {
            enqueue(Request.newReadRequest(service.getCharacteristic(BLE_BATTERY_CHARACTERISTIC)));
        }
    }

    public void readDeviceName() {
        BluetoothGattService service = this.mBluetoothGatt.getService(BLE_GAP_SERVICE);
        if (service != null) {
            enqueue(Request.newReadRequest(service.getCharacteristic(BLE_GAP_DEVICENAME_CHARACTERISTIC)));
        }
    }

    public void writeDeviceName00() {
        byte[] byteArray = new byte[1];
        byteArray[0] = 0x00;
        BluetoothGattService service = this.mBluetoothGatt.getService(UUID.fromString(BLEAttributes.BLE_FTMS_SERVICE));
        if (service != null) {
            enqueue(Request.newWriteRequest(service.getCharacteristic(UUID.fromString(BLEAttributes.BLE_FTMS_CHAR_CONTROL_POINT)), byteArray));
        }
    }

    public void writeDeviceName07() {
        byte[] byteArray = new byte[1];
        byteArray[0] = 0x07;
        BluetoothGattService service = this.mBluetoothGatt.getService(UUID.fromString(BLEAttributes.BLE_FTMS_SERVICE));
        if (service != null) {
            enqueue(Request.newWriteRequest(service.getCharacteristic(UUID.fromString(BLEAttributes.BLE_FTMS_CHAR_CONTROL_POINT)), byteArray));
        }
    }

    public void readHeartRateBodyLocation() {
        BluetoothGattService service = this.mBluetoothGatt.getService(BLE_HEART_RATE_BODY_LOCATION_SERVICE);
        if (service != null) {
            BluetoothGattCharacteristic characteristic = service.getCharacteristic(BLE_HEART_RATE_BODY_LOCATION_CHARACTERISTIC);
            if (service.getCharacteristics().contains(characteristic)) {
                enqueue(Request.newReadRequest(characteristic));
            }
        }
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic btGattCharacter, boolean z) {
        enqueue(Request.newEnableNotificationsRequest(btGattCharacter));
    }

    public void requestConnectionPriority(int i) {
        if (Build.VERSION.SDK_INT >= 21) {
            enqueue(Request.newConnectionPriorityRequest(i));
        }
    }

    public boolean isServicesDiscovered() {
        return getConnectionState() == 8;
    }

    protected void sendBroadcast(Intent intent) {
        intent.setPackage(this.mAppContext.getPackageName());
        this.mAppContext.sendBroadcast(intent);
    }

    public void handleMessage(Message message) {
        int i = message.what;
        Log.d("wangsm_bt", " AbsBleDevice, handlemessage,msg.what " + i);
        if (i == OP_CONNECT) {
            /*
             * SmartDevice smartDevice = getDevice(); Log.d(TAG," OP_CONNECT: " ); if(smartDevice != null){ int type =
             * smartDevice.getType(); Log.d(TAG," the type is: " + type); if(type == SmartDevice.TYPE_BES){ boolean
             * existDeviceConnted = DeviceHelper.isConnected(SmartDevice.TYPE_BES); Log.d(TAG, " existDeviceConnted: " +
             * existDeviceConnted); if(!existDeviceConnted){ connectBesDevice(); } return; } }
             */
            _connect();
        } else if (i == OP_RECONNECT) {
            Log.d(TAG, " OP_RECONNECT: ");
            _reconnect();
        } else if (i == OP_DISCOVER_SERVICES) {
            onServicesDiscovered();
        } else if (i == OP_DISCONNECT) {
            _disconnect();
        } else if (i == OP_CLOSE) {
            _close();
        } else if (i == OP_DISPATCH_STATUS) {
            if (onStateChanged(message.arg1, message.arg2)) {
                return;
            }
            notifyStateChanged(message.arg1, message.arg2);
        } else if (i == OP_EXECUTE_REQUEST) {
            _executeOnce((Request) message.obj);
        } else if (i == OP_REQUEST_MTU_TIMEOUT) {
            handleMtuRequest(257, this.mtuExchanged);
        }
    }

    public final boolean execute(Request request) {
        return isServicesDiscovered() && _executeOnce(request);
    }

    public final boolean enqueue(Request request) {
        if (isServicesDiscovered()) {
            return this.mLocalHandler.sendMessage(this.mLocalHandler.obtainMessage(OP_EXECUTE_REQUEST, request));
        }
        return false;
    }

    public void notifyRequestResult(int i) {
        synchronized (this.mLock) {
            this.mRequestResult = i;
            this.mLock.notifyAll();
        }
    }

    private boolean _executeOnce(Request request) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "_executeOnce: permission check not granted!");
                return false;
            }
        }
        boolean readCharacteristic;
        if (request.characteristic == null) {
            return false;
        }
        long currentTimeMillis = System.currentTimeMillis();
        this.mRequestResult = -1;

        if (request.type == Request.Type.READ) {
            readCharacteristic = readCharacteristic(request.characteristic);
        } else if (request.type == Request.Type.WRITE) {
            BluetoothGattCharacteristic bluetoothGattCharacteristic = request.characteristic;
            boolean value = bluetoothGattCharacteristic.setValue((byte[]) request.value);
            writeCharacteristic(bluetoothGattCharacteristic);
            readCharacteristic = value;
        } else if (request.type == Request.Type.ENABLE_NOTIFICATIONS) {
            readCharacteristic = enableNotifications(request.characteristic);
        } else if (request.type == Request.Type.ENABLE_INDICATIONS) {
            readCharacteristic = enableIndications(request.characteristic);
        } else if (request.type == Request.Type.REQUEST_CONNECTION_PRIORITY) {
            if (Build.VERSION.SDK_INT < 21) {
                return true;
            }
            boolean requestConnectionPriority = this.mBluetoothGatt.requestConnectionPriority((Integer) request.value);
            Log.d(TAG, "connection priority: " + request.value);
            return requestConnectionPriority;
        } else {
            readCharacteristic = false;
        }
        synchronized (this.mLock) {
            try {
                if (this.mRequestResult == -1) {
                    this.mLock.wait(2000L);
                }
                Log.d(TAG, "Exec duration: " + (System.currentTimeMillis() - currentTimeMillis));
                Log.d(TAG, String.format(Locale.getDefault(), "Exec result(%d): %s", this.mRequestResult, GattError.parse(this.mRequestResult)));
            } catch (InterruptedException e) {
                Log.e(TAG, "exception e=" + e);
            }
        }
        if (this.mRequestResult != 0 && request.retryTimes > 0) {
            request.retryTimes--;
            enqueue(request);
        }
        return readCharacteristic && this.mRequestResult == 0;
    }

    // private int getRequestTypeId(Request.Type strType) {
    // int typeId = 0;
    // switch (strType) {
    // case READ -> {
    // typeId = 1;
    // }
    // case WRITE -> {
    // typeId = 2;
    // }
    // case ENABLE_NOTIFICATIONS -> {
    // typeId = 3;
    // }
    // case ENABLE_INDICATIONS -> {
    // typeId = 4;
    // }
    // case REQUEST_CONNECTION_PRIORITY -> {
    // typeId = 5;
    // }
    // default -> {
    // }
    // }
    // return typeId;
    // }

    protected final boolean enableNotifications(BluetoothGattCharacteristic btGattCharacter) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "enableNotifications: permission check not granted!");
                return false;
            }

        }
        BluetoothGatt bluetoothGatt = this.mBluetoothGatt;
        if (bluetoothGatt == null || btGattCharacter == null || (btGattCharacter.getProperties() & OP_SHIFT) == 0) {
            return false;
        }
        Log.d(TAG, "gatt.setCharacteristicNotification(" + btGattCharacter.getUuid() + ", true)");
        bluetoothGatt.setCharacteristicNotification(btGattCharacter, true);
        BluetoothGattDescriptor descriptor = btGattCharacter.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG2);
        if (descriptor != null) {
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            Log.d(TAG, "Enabling notifications for " + btGattCharacter.getUuid());
            Log.d(TAG, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG2 + ", value=0x01-00)");
            return bluetoothGatt.writeDescriptor(descriptor);
        }
        return false;
    }

    protected final boolean enableIndications(BluetoothGattCharacteristic btGattCharacter) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "enableIndications: permission check not granted!");
                return false;
            }
        }
        if (this.mBluetoothGatt != null && btGattCharacter != null && (btGattCharacter.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
            Log.d(TAG, "gatt.setCharacteristicNotification(" + btGattCharacter.getUuid() + ", true)");
            this.mBluetoothGatt.setCharacteristicNotification(btGattCharacter, true);
            BluetoothGattDescriptor descriptor = btGattCharacter.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG2);
            if (descriptor != null) {
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                Log.d(TAG, "Enabling indications for " + btGattCharacter.getUuid());
                Log.d(TAG, "gatt.writeDescriptor(" + CLIENT_CHARACTERISTIC_CONFIG2 + ", value=0x02-00)");
                return this.mBluetoothGatt.writeDescriptor(descriptor);
            }
        }
        return false;
    }

    public final boolean readCharacteristic(BluetoothGattCharacteristic btGattCharacter) {
        Log.d(TAG, "readCharacteristic btGattCharacter=" + btGattCharacter);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "readCharacteristic: permission check not granted!");
                return false;
            }
        }
        if (this.mBluetoothGatt != null && btGattCharacter != null && (btGattCharacter.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0) {
            Log.d(TAG, "Reading characteristic " + btGattCharacter.getUuid());
            Log.d(TAG, "gatt.readCharacteristic(" + btGattCharacter.getUuid() + Separators.RPAREN);
            return this.mBluetoothGatt.readCharacteristic(btGattCharacter);
        } else {
            return false;
        }
    }

    protected final boolean writeCharacteristic(BluetoothGattCharacteristic btGattCharacter) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(mAppContext, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                Log.w(TAG, "writeCharacteristic: permission check not granted!");
                return false;
            }
        }
        if (this.mBluetoothGatt != null && btGattCharacter != null && (btGattCharacter.getProperties() & (BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE | BluetoothGattCharacteristic.PROPERTY_WRITE)) != 0) {
            Log.d(TAG, "Writing characteristic " + btGattCharacter.getUuid() + " (" + getWriteType(btGattCharacter.getWriteType()) + Separators.RPAREN);
            StringBuilder sb = new StringBuilder();
            sb.append("gatt.writeCharacteristic(");
            sb.append(btGattCharacter.getUuid());
            sb.append(Separators.RPAREN);
            Log.d(TAG, sb.toString());
            return this.mBluetoothGatt.writeCharacteristic(btGattCharacter);
        } else {
            return false;
        }
    }

    protected String getWriteType(int i) {
        if (i != 1) {
            if (i == 2) {
                return "WRITE REQUEST";
            }
            if (i == 4) {
                return "WRITE SIGNED";
            }
            return "UNKNOWN: " + i;
        }
        return "WRITE COMMAND";
    }

    private void reportError(int i) {
        if (i != 0) {
            StringBuilder sb = new StringBuilder();
            sb.append(" ERROR(");
            sb.append(i);
            sb.append(") --> ");
            if (i == ERROR_BLUETOOTH) {
                sb.append("Bluetooth unavailable");
            } else if (i == ERROR_TIMEOUT) {
                sb.append("Operation timeout");
            } else if (i == ERROR_CONNECT_LOSE) {
                sb.append("Connection lost");
            } else if (i == ERROR_NOT_FOUND_DEVICE) {
                sb.append("Not found device");
            } else if (i == ERROR_DEVICE_BUSY) {
                sb.append("Device busy or not active");
            } else {
                sb.append("Unknown");
            }
            Log.e(TAG, sb.toString());
        }
    }

    @Override
    public String getTag() {
        return "GattClient-" + getName();
    }

    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        AbsBleDevice absBleDevice = (AbsBleDevice) obj;
        BluetoothDevice bluetoothDevice = this.mBluetoothDevice;
        if (bluetoothDevice == null ? absBleDevice.mBluetoothDevice != null : !bluetoothDevice.equals(absBleDevice.mBluetoothDevice)) {
            return false;
        }
        String str = this.mDeviceAddress;
        String str2 = absBleDevice.mDeviceAddress;
        return str != null ? str.equals(str2) : str2 == null;
    }

    public int hashCode() {
        String str = this.mDeviceAddress;
        if (str != null) {
            return str.hashCode();
        }
        return 0;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable th) {
        Log.e(TAG, "Uncaught exception occurs: th=" + th);
    }

    public static final class Request {
        private final BluetoothGattCharacteristic characteristic;
        private final Type type;
        private final Object value;
        private int retryTimes;

        private Request(Type type, Object obj) {
            this(type, null, obj);
        }

        private Request(Type type, BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            this.type = type;
            this.characteristic = bluetoothGattCharacteristic;
            this.value = null;
        }

        private Request(Type type, BluetoothGattCharacteristic bluetoothGattCharacteristic, Object obj) {
            this(type, bluetoothGattCharacteristic, obj, 0);
        }

        private Request(Type type, BluetoothGattCharacteristic bluetoothGattCharacteristic, Object obj, int i) {
            this.type = type;
            this.characteristic = bluetoothGattCharacteristic;
            this.value = obj;
            this.retryTimes = i;
        }

        public static Request newReadRequest(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            return new Request(Type.READ, bluetoothGattCharacteristic);
        }

        public static Request newWriteRequest(BluetoothGattCharacteristic bluetoothGattCharacteristic, byte[] bArr) {
            return new Request(Type.WRITE, bluetoothGattCharacteristic, bArr);
        }

        public static Request newEnableNotificationsRequest(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            return new Request(Type.ENABLE_NOTIFICATIONS, bluetoothGattCharacteristic, null, 1);
        }

        public static Request newEnableIndicationsRequest(BluetoothGattCharacteristic bluetoothGattCharacteristic) {
            return new Request(Type.ENABLE_INDICATIONS, bluetoothGattCharacteristic);
        }

        public static Request newConnectionPriorityRequest(int i) {
            return new Request(Type.REQUEST_CONNECTION_PRIORITY, null, i);
        }

        public enum Type {
            WRITE, READ, ENABLE_NOTIFICATIONS, ENABLE_INDICATIONS, REQUEST_CONNECTION_PRIORITY
        }
    }
}
